﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Sausage.Common;
using Sausage.Web.DataModel;
using Sausage.Web.Models;
using System.Web;

namespace Sausage.Web.Domain
{
    public class OrganizationHelper
    {
        static OrganizationHelper()
        {
        }

        /// <summary>
        /// 组织结构缓存键值
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2012/03/14 17:13    创建
        /// </history>
        public const string ORGANIZATION_CACHE_KEY = "CACHE_ORGANIZATION";

        /// <summary>
        /// 获得组织结构列表。
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2012/03/14 17:03    创建
        /// </history>
        private static IList<Organization> OrganizationList
        {
            get
            {
                //获得缓存的组织结构列表
                IList<Organization> organizations = HttpContext.Current.Cache.Get(ORGANIZATION_CACHE_KEY) as IList<Organization>;

                //判断缓存是否存在
                if (null == organizations)
                {
                    //获得组织结构列表
                    using (SausageEntities context = new SausageEntities())
                    {
                        //查询组织结构列表
                        organizations = context.Organization.OrderBy(item => item.OrganizationCode).ToArray();
                    }

                    //添加到缓存
                    HttpContext.Current.Cache.Add(ORGANIZATION_CACHE_KEY, organizations, null, DateTime.MaxValue, TimeSpan.Zero, System.Web.Caching.CacheItemPriority.Normal, null);
                }

                //返回组织结构
                return organizations;
            }
        }

        public static Organization GetOrganizationByID(Guid? organizationID)
        {
            if (!organizationID.HasValue)
                return null;

            using (var context = new SausageEntities())
            {
                return context.Organization.FirstOrDefault(organization => organization.OrganizationID == organizationID.Value);
            }
        }

        public static List<Organization> GetOrganizationList()
        {
            using (var context = new SausageEntities())
            {
                return context.Organization.OrderBy(item => item.OrganizationCode).ToList();
            }
        }

        public static List<Organization> GetAllowedOrganization()
        {

            var list = new List<Organization>(32);
            list.Add(Helper.CurrentPrincipal.Organization);
            GetChildren(Helper.CurrentPrincipal.Organization.OrganizationID, OrganizationList, list);
            return list;
        }

        public static List<Guid> GetAllowedOrganizationList()
        {
            var list = new List<Guid>(32);
            list.Add(Helper.CurrentPrincipal.User.OrganizationID);
            GetChildren(Helper.CurrentPrincipal.Organization.OrganizationID, OrganizationList, list);
            return list;
        }

        public static List<Guid> GetAllowedOrganizationList(Guid targetID)
        {
            var list = new List<Guid>(32);
            list.Add(targetID);
            GetChildren(targetID, OrganizationList, list);
            return list;
        }

        public static List<Guid> GetAllowedOrganizationList(bool needFilter, Guid targetID)
        {
            if (needFilter)
            {
                return GetAllowedOrganizationList(targetID);
            }
            else if (targetID != Guid.Empty)
            {
                return new Guid[] { targetID }.ToList();
            }
            else
            {
                return GetAllowedOrganizationList();
            }
        }

        public static IEnumerable<TreeNodeData> QueryOrganizationTree()
        {
            using (var context = new SausageEntities())
            {
                return GetChildren(null, context.Organization.ToList());
            }
        }

        public static IEnumerable<CheckTreeNode> QueryOrganizationCheckTree(Organization parent, int[] types)
        {
            using (var context = new SausageEntities())
            {
                //创建根节点
                CheckTreeNode root = new CheckTreeNode()
                {
                    id = parent.OrganizationID,
                    expanded = true,
                    leaf = false,
                    text = string.Format("{0} {1}", parent.OrganizationCode, parent.OrganizationName),
                    @checked = false,
                    parentID = null,
                    data = GetCheckTreeNode(parent.OrganizationID, context.Organization.ToList(), types)
                };

                //返回结果
                return new CheckTreeNode[] { root };
            }
        }

        private static IEnumerable<CheckTreeNode> GetCheckTreeNode(Guid parentID, IEnumerable<Organization> organizationList, int[] types)
        {
            var children = from item in organizationList
                           where item.ParentID == parentID && Array.IndexOf<int>(types, item.Category) != -1
                           orderby item.OrganizationCode
                           select new CheckTreeNode
                            {
                                id = item.OrganizationID,
                                expanded = true,
                                leaf = item.IsLeaf,
                                text = string.Format("{0} {1}", item.OrganizationCode, item.OrganizationName),
                                @checked = false,
                                parentID = item.ParentID,
                                data = GetCheckTreeNode(item.OrganizationID, organizationList, types)
                            };

            return children;
        }

        private static void GetChildren(Guid? parentID, IEnumerable<Organization> organizationList, List<Organization> result)
        {
            var children = (from organization in organizationList
                            where organization.ParentID == parentID
                            orderby organization.OrganizationCode
                            select organization);

            result.AddRange(children);

            foreach (var organization in children)
            {
                GetChildren(organization.OrganizationID, organizationList, result);
            }
        }

        private static void GetChildren(Guid? parentID, IEnumerable<Organization> organizationList, List<Guid> result)
        {
            var children = (from organization in organizationList
                            where organization.ParentID == parentID
                            orderby organization.OrganizationCode
                            select organization.OrganizationID);

            result.AddRange(children);

            foreach (var organization in children)
            {
                GetChildren(organization, organizationList, result);
            }
        }

        private static IEnumerable<TreeNodeData> GetChildren(Guid? parentID, IEnumerable<Organization> organizationList)
        {
            var children = from organization in organizationList
                           where organization.ParentID == parentID
                           orderby organization.OrganizationCode
                           select
                               new TreeNodeData
                               {
                                   id = organization.OrganizationID,
                                   expanded = organization.Category == 0,
                                   leaf = organization.IsLeaf,
                                   name = organization.OrganizationName,
                                   parentID = organization.ParentID,
                                   code = organization.OrganizationCode,
                                   category = organization.Category,
                                   categoryName = Utility.GetCategoyNameByCode(organization.Category),
                                   data = GetChildren(organization.OrganizationID, organizationList)
                               };

            return children;
        }

        public static Organization GetOrganizationByID(Guid id)
        {
            using (var context = new SausageEntities())
            {
                return context.Organization.FirstOrDefault(organization => organization.OrganizationID == id);
            }
        }

        public static DeleteResult DeleteOrganization(Guid id)
        {
            using (var context = new SausageEntities())
            {
                var organization = context.Organization.FirstOrDefault(item => item.OrganizationID == id);
                if (organization == null || !organization.IsLeaf)
                    return DeleteResult.Ok;

                //just delete the leaf node.
                if (organization.ParentID.HasValue)
                {
                    var brothers = context.Organization.Where(item => item.ParentID == organization.ParentID).ToList();
                    if (brothers.Count <= 1)
                    {
                        var parent = context.Organization.FirstOrDefault(item => item.OrganizationID == organization.ParentID.Value);
                        if (parent != null)
                            parent.IsLeaf = true;
                    }
                }

                context.ObjectStateManager.ChangeObjectState(organization, EntityState.Deleted);
                try
                {
                    context.SaveChanges();
                }
                catch (UpdateException)
                {
                    return DeleteResult.UsingError;
                }
                return DeleteResult.Ok;
            }
        }

        public static void UpdateOrganization(TreeNodeData data)
        {
            using (var context = new SausageEntities())
            {
                var organization = context.Organization.FirstOrDefault(item => item.OrganizationID == data.id);
                if (organization == null)
                    return;

                organization.OrganizationName = data.name;
                organization.OrganizationCode = data.code;
                organization.Category = data.category;

                context.SaveChanges();
            }
        }

        public static Organization GetOrganizationByName(string name)
        {
            using (var context = new SausageEntities())
            {
                return context.Organization.FirstOrDefault(organization => organization.OrganizationName == name);
            }
        }

        public static Organization GetOrganizationByCode(string code)
        {
            using (var context = new SausageEntities())
            {
                return context.Organization.FirstOrDefault(organization => organization.OrganizationCode == code);
            }
        }

        public static void CreateOrganization(TreeNodeData data)
        {
            using (var context = new SausageEntities())
            {
                var organization = new Organization();

                organization.OrganizationID = Guid.NewGuid();
                organization.ParentID = data.parentID;
                organization.OrganizationName = data.name;
                organization.OrganizationCode = data.code;
                organization.Category = data.category;
                organization.TheOrder = 0;
                organization.IsLeaf = true;

                if (data.parentID.HasValue)
                {
                    var parent = context.Organization.FirstOrDefault(item => item.OrganizationID == data.parentID.Value);
                    parent.IsLeaf = false;
                }

                context.AddToOrganization(organization);
                context.SaveChanges();
            }
        }

        public static readonly Guid DistrictOrganization = Guid.Parse("D1097D58-178A-458E-96DF-E8D0CD98027C");

        public static bool IsDistrictOrganization(Guid organizationID)
        {
            return organizationID == DistrictOrganization;
        }
    }
}
